/**
 * Copyright 2009 by Nathaniel Harward.
 * 
 * This file is part of jtyrant-net.
 * 
 * jtyrant-net is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * jtyrant-net is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with jtyrant-net.  If not, see <http://www.gnu.org/licenses/>
 */
package us.harward.jtn;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.channels.ByteChannel;
import java.nio.channels.SocketChannel;

/**
 * Provides a handful of ways to create new connections; these are simply
 * shorthand ways to get at a {@link Socket} object to pass to the
 * {@link TokyoTyrantConnection} constructor.
 * 
 * All methods use the assert keyword to verify that their arguments are non-
 * <code>null</code> and otherwise are acceptable -- if you disable assertions
 * you will bypass these checks.
 * 
 * If you require specific tuning, please use
 * {@link #newConnection(SocketChannel)} to use a pre-tuned
 * {@link SocketChannel} as-is.
 */
public final class TokyoTyrantConnectionFactory {

    /**
     * Default is "localhost".
     */
    public static final String DEFAULT_HOST = "localhost";

    /**
     * Default Tokyo Tyrant port is 1978.
     */
    public static final int DEFAULT_PORT = 1978;

    /**
     * Equivalent to calling <code>newConnection(DEFAULT_HOST, DEFAULT_PORT).
     */
    public static TokyoTyrantConnection newConnection()
	    throws UnknownHostException, IOException {
	return newConnection(DEFAULT_HOST, DEFAULT_PORT);
    }

    /**
     * Equivalent to calling <code>newConnection(remoteHost, DEFAULT_PORT).
     */
    public static TokyoTyrantConnection newConnection(final String remoteHost)
	    throws UnknownHostException, IOException {
	return newConnection(remoteHost, DEFAULT_PORT);
    }

    /**
     * @param remoteHost
     *            the hostname of the remote Tokyo Tyrant server
     * @param remotePort
     *            the port of the remote Tokyo Tyrant server
     * @return a connected {@link TokyoTyrantConnection} object
     * @throws UnknownHostException
     * @throws IOException
     */
    public static TokyoTyrantConnection newConnection(final String remoteHost,
	    final int remotePort) throws UnknownHostException, IOException {
	assert remoteHost != null : "Remote host cannot be null";
	assert remotePort >= 0 : "Remote port must be greater than 0";
	return new TokyoTyrantConnection(SocketChannel
		.open(new InetSocketAddress(remoteHost, remotePort)));
    }

    /**
     * Equivalent to calling
     * <code>newConnection(remoteHost, DEFAULT_PORT)</code>
     */
    public static TokyoTyrantConnection newConnection(
	    final InetAddress remoteHost) throws IOException {
	assert remoteHost != null : "Remote host cannot be null";
	return newConnection(remoteHost, DEFAULT_PORT);
    }

    /**
     * @param remoteHost
     *            the hostname of the remote Tokyo Tyrant server
     * @param remotePort
     *            the port of the remote Tokyo Tyrant server
     * @return a connected {@link TokyoTyrantConnection} object
     * @throws IOException
     */
    public static TokyoTyrantConnection newConnection(
	    final InetAddress remoteHost, final int remotePort)
	    throws IOException {
	assert remoteHost != null : "Remote host cannot be null";
	assert remotePort >= 0 : "Remote port must be greater than 0";
	return new TokyoTyrantConnection(SocketChannel
		.open(new InetSocketAddress(remoteHost, remotePort)));
    }

    /**
     * @param remoteSocketAddress
     *            the endpoint of the remote Tokyo Tyrant server
     * @return a connected {@link TokyoTyrantConnection} object
     * @throws IOException
     */
    public static TokyoTyrantConnection newConnection(
	    final SocketAddress remoteSocketAddress) throws IOException {
	assert remoteSocketAddress != null : "Remote socket address cannot be null";
	return new TokyoTyrantConnection(SocketChannel
		.open(remoteSocketAddress));
    }

    /**
     * It is likely that this will be a {@link SocketChannel} object, however
     * any channel supporting the Tokyo Tyrant protocol can be used (for mocking
     * up a test server, for example).
     * 
     * @param channel
     *            an existing, connected channel
     * @return a connected {@link TokyoTyrantConnection} object
     * @throws IOException
     */
    public static TokyoTyrantConnection newConnection(final ByteChannel channel)
	    throws IOException {
	assert channel != null : "Channel cannot be null";
	return new TokyoTyrantConnection(channel);
    }
}
